﻿using System;
using System.Collections;
using System.Threading;
using Seovic.Identity;

namespace Seovic.Identity
{
    /// <summary>
    /// Multi-threaded test client for <see cref="IIdentityGenerator"/> implementations.
    /// </summary>
    /// <author>Aleksandar Seovic  2008.11.24</author>
    /// <author>Ivan Cikic  2009.10.29</author>
    public class IdentityGeneratorClient<T>
    {
        #region Constructors

        /// <summary>
        /// Construct IdentityGeneratorClient instance.
        /// </summary>
        /// <param name="generator">Identity generator to test</param>
        public IdentityGeneratorClient(IIdentityGenerator<T> generator)
        {
            this.generator = generator;
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Starts specified number of identity generation threads, each of which
        /// should generate the specified number of identities.
        /// </summary>
        /// <param name="numThreads">number of identity generation threads to start</param>
        /// <param name="numIdentities">number of identities to generate (per thread)</param>
        /// <returns>a collection of identities generated by all threads</returns>
        public ICollection GenerateIdentities(int numThreads, int numIdentities)
        {
            IList identities = ArrayList.Synchronized(new ArrayList());
            EventWaitHandle   start = new ManualResetEvent(false);
            EventWaitHandle[] tasksDone = new EventWaitHandle[numThreads];
            try
            {
                for (int i = 0; i < numThreads; i++)
                {
                    tasksDone[i] = new AutoResetEvent(false);
                }
                for (int i = 0; i < numThreads; i++)
                {
                    Thread t = new Thread(IdGenerator);
                    var context = new object[] {identities, numIdentities, start, tasksDone[i]};
                    t.Start(context);
                }
                Console.WriteLine("Opened gate for start handle");
                start.Set();
                Console.WriteLine("Waiting for done handles");
                WaitHandle.WaitAll(tasksDone);
                Console.WriteLine("All done handles singnaled");
                return identities;
            }
            finally
            {
                start.Close();
                foreach (EventWaitHandle wh in tasksDone)
                {
                    wh.Close();
                }
            }
        }

        #endregion

        #region Delgates

        private void IdGenerator(object context)
        {
            object[] array = (object[]) context;
            IList identities = (IList)array[0];
            int numIdentities = (int)array[1];
            EventWaitHandle start = (EventWaitHandle)array[2];
            EventWaitHandle done = (EventWaitHandle) array[3];
            Random    randomizer   = new Random();
            Console.WriteLine(Thread.CurrentThread.Name + "waiting for start handle");
            start.WaitOne();
            Console.WriteLine(Thread.CurrentThread.Name + "passed the start gate");
            for (int i = 0; i < numIdentities; i++)
            {
                identities.Add(generator.GenerateIdentity());
                Thread.Sleep(randomizer.Next(10));
            }
            Console.WriteLine(Thread.CurrentThread.Name + "signals to done handle");
            done.Set();
        }

        #endregion

        #region Data members

        /// <summary>
        /// IIdentityGenerator to test.
        /// </summary>
        private IIdentityGenerator<T> generator;

        #endregion

        
    }
}
